﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;

namespace Workflows.Components.Reports
{
	/// <summary>
	/// 
	/// </summary>
	[Serializable]
	public class SetOperation:IComparable
	{
        private int _Order;
        /// <summary></summary>
        public int Order
        {
            get
            {
                return this._Order;
            }
            set
            {
                this._Order = value;
            }
        }

		private string[] _SetNames;
		/// <summary>
		/// one or two affected sets
		/// </summary>
		public string[] SetNames
		{
			get
			{
				return this._SetNames;
			}
			set
			{
				this._SetNames = value;
			}
		}

		private string _Formular;
		/// <summary>
		/// [set]>("where clause or xpath") : filter
		/// [set1]+[set2] : union
		/// [set1]-[set2] : exclude
		/// [set1]/[set2] : intersection
		/// </summary>
		public string Formular
		{
			get
			{
				return this._Formular;
			}
			set
			{
				this._Formular = value;
			}
		}

		private string _OutputSetName;
		/// <summary></summary>
		public string OutputSetName
		{
			get
			{
				return this._OutputSetName;
			}
			set
			{
				this._OutputSetName = value;
			}
		}

		/// <summary>
		/// 
		/// </summary>
		public SetManipulationMethod OpType
		{
			get
			{
				SetManipulationMethod method = SetManipulationMethod.Union;
				if (this.Formular.IndexOf(">") > 0)
				{
					method = SetManipulationMethod.Filter;
				}
				else if (this.Formular.IndexOf("+") > 0)
				{
					method = SetManipulationMethod.Union;
				}
				else if (this.Formular.IndexOf("-") > 0)
				{
					method = SetManipulationMethod.Exclude;
				}
				else
				{
					method = SetManipulationMethod.Intersection;
				}
				return method;
			}
		}

		/// <summary>
		/// 
		/// </summary>
		public string FilterClause
		{
			get
			{
				string filterClause = string.Empty;
				if(this.OpType==SetManipulationMethod.Filter)
				{
					Regex setNameRegex = new Regex(@"\[?([^>\[\]\{\}]+)\]?>(.+)");
					Match setNameMatch = setNameRegex.Match(this.Formular);
					if (setNameMatch.Success)
					{
						filterClause = setNameMatch.Groups[2].Value;
					}
				}
				return filterClause;
			}
		}

		/// <summary>
		/// 
		/// </summary>
		/// <param name="order"></param>
		/// <param name="setNames"></param>
		/// <param name="formular"></param>
		/// <param name="outputSetName"></param>
		public SetOperation(int order, string[] setNames, string formular, string outputSetName)
		{
		    this._Order = order;
			this._SetNames = setNames;
			this._Formular = formular;
			this._OutputSetName = outputSetName;
		}

		/// <summary>
		/// 
		/// </summary>
		/// <param name="method"></param>
		/// <param name="setName1"></param>
		/// <param name="setName2"></param>
		/// <param name="filterClause"></param>
		public void ParseFormular(out SetManipulationMethod method, out string setName1, out string setName2, out string filterClause)
		{
			filterClause = string.Empty;
			if(this.Formular.IndexOf(">")>0)
			{
				method = SetManipulationMethod.Filter;
				Regex setNameRegex = new Regex(@"\[?([^>\[\]\{\}]+)\]?>(.+)");
				Match setNameMatch = setNameRegex.Match(this.Formular);
				if(setNameMatch.Success)
				{
					setName1 = setNameMatch.Groups[1].Value;
					filterClause = setNameMatch.Groups[2].Value;
				}
				else
					setName1 = string.Empty;
				setName2 = null;
			}
			else if(this.Formular.IndexOf("+")>0)
			{
				method = SetManipulationMethod.Union;
				Regex setNameRegex = new Regex(@"\[?([^\[\]\{\}]+)\]?\+\[?([^\[\]\{\}]+)\]?");
				Match setNameMatch = setNameRegex.Match(this.Formular);
				if (setNameMatch.Success)
				{
					setName1 = setNameMatch.Groups[1].Value;
					setName2 = setNameMatch.Groups[2].Value;
				}
				else
				{
					setName1 = string.Empty;
					setName2 = string.Empty;
				}
			}
			else if(this.Formular.IndexOf("-")>0)
			{
				method = SetManipulationMethod.Exclude;
				Regex setNameRegex = new Regex(@"\[?([^\[\]\{\}]+)\]?-\[?([^\[\]\{\}]+)\]?");
				Match setNameMatch = setNameRegex.Match(this.Formular);
				if (setNameMatch.Success)
				{
					setName1 = setNameMatch.Groups[1].Value;
					setName2 = setNameMatch.Groups[2].Value;
				}
				else
				{
					setName1 = string.Empty;
					setName2 = string.Empty;
				}
			}
			else
			{
				method = SetManipulationMethod.Intersection;
				Regex setNameRegex = new Regex(@"\[?([^\[\]\{\}]+)\]?/\[?([^\[\]\{\}]+)\]?");
				Match setNameMatch = setNameRegex.Match(this.Formular);
				if (setNameMatch.Success)
				{
					setName1 = setNameMatch.Groups[1].Value;
					setName2 = setNameMatch.Groups[2].Value;
				}
				else
				{
					setName1 = string.Empty;
					setName2 = string.Empty;
				}
			}
		}

	    #region Implementation of IComparable

	    /// <summary>
	    ///                     Compares the current instance with another object of the same type and returns an integer that indicates whether the current instance precedes, follows, or occurs in the same position in the sort order as the other object.
	    /// </summary>
	    /// <returns>
	    ///                     A 32-bit signed integer that indicates the relative order of the objects being compared. The return value has these meanings: 
	    ///                     Value 
	    ///                     Meaning 
	    ///                     Less than zero 
	    ///                     This instance is less than <paramref name="obj" />. 
	    ///                     Zero 
	    ///                     This instance is equal to <paramref name="obj" />. 
	    ///                     Greater than zero 
	    ///                     This instance is greater than <paramref name="obj" />. 
	    /// </returns>
	    /// <param name="obj">
	    ///                     An object to compare with this instance. 
	    ///                 </param>
	    /// <exception cref="T:System.ArgumentException"><paramref name="obj" /> is not the same type as this instance. 
	    ///                 </exception><filterpriority>2</filterpriority>
	    public int CompareTo(object obj)
	    {
            if (obj.GetType() == typeof(SetOperation))
            {
                SetOperation otherOp = (SetOperation)obj;
                return this.Order.CompareTo(otherOp.Order);
            }
            else
                return 0;
	    }

	    #endregion
	}
}
